package javagamecontroller.activities.controllers;


import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.os.Vibrator;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import javagamecontroller.connection.BluetoothMessenger;
import util.input.android.events.AndroidButtonEvent;


/**
 * This class lays out a group of images in a grid to form buttons. It send
 * button events whenever one of these buttons is either pushed or released.
 * To use this class you must subclass it and implement the
 * iniatlizeController() method where you create a map of Images to
 * gridlocations, and a map of
 * grid locations to the proper controller id number.
 * 
 * @author Lance, Ben
 * 
 */
public abstract class ButtonManager extends BaseAdapter {

    protected static final int NUM_BUTTONS = 24;
    protected static final int PRESS_VIBRATE_TIME = 13;
    protected static final int RELEASE_VIBRATE_TIME = 7;
    protected static final int EMPTY_CELL = -1;
    private static final int CELL_SIZE = 71;
    private int mySelectButtonLocation;
    private Context myContext;
    private Map<Integer, AndroidButton> myButtonImageMap;
    private BluetoothMessenger myMessenger;
    private Map<Integer, Integer> myButtonIDMap;
    private Vibrator myVibrator;

    private ControllerFrame myFrame;

    /**
     * Create a new button manager
     * 
     * @param c the frame that holds the button manager
     * @param vibrator the vibrator that will be used on a button event
     */
    public ButtonManager (ControllerFrame c, Vibrator vibrator) {
        myVibrator = vibrator;
        myButtonImageMap = new HashMap<Integer, AndroidButton>();
        myButtonIDMap = new HashMap<Integer, Integer>();
        myContext = c;
        myFrame = c;
        myMessenger = BluetoothMessenger.getInstance();
        initializeController();
    }

    @Override
    public int getCount () {
        return NUM_BUTTONS;
    }

    @Override
    public Object getItem (int position) {
        return null;
    }

    @Override
    public long getItemId (int position) {
        return 0;
    }

    @Override
    public View getView (int position, View convertView, ViewGroup parent) {
        ImageView imageView;
        if (convertView == null) {

            imageView = new ImageView(myContext);
            imageView.setLayoutParams(new GridView.LayoutParams(CELL_SIZE, CELL_SIZE));
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setPadding(2, 2, 2, 2);
        }
        else {
            imageView = (ImageView) convertView;
        }

        if (myButtonImageMap.containsKey(position)) {
            Log.e("imageadapter", position + "");
            imageView.setImageResource(myButtonImageMap.get((Integer) position).getDrawState());
            imageView.setOnTouchListener(getGridButtonTouchListener(position));
        }
        else {
            imageView.setClickable(false);
            imageView.setFocusable(false);
            imageView.setOnTouchListener(getGridButtonTouchListener(EMPTY_CELL));
        }
        return imageView;
    }

    abstract void initializeController ();

    protected void setSelectButton (int selectLocation) {
        mySelectButtonLocation = selectLocation;
    }

    protected int getSelectButtonLocation () {
        return mySelectButtonLocation;
    }

    protected Map<Integer, AndroidButton> getButtonImageMap () {
        return myButtonImageMap;
    }

    protected Map<Integer, Integer> getButtonIdMap () {
        return myButtonIDMap;
    }

    private OnTouchListener getGridButtonTouchListener (final int position) {
        return new OnTouchListener() {

            @Override
            public boolean onTouch (View v, MotionEvent event) {
                if (position == EMPTY_CELL) { return true; }
                if (position == getSelectButtonLocation()) {
                    myFrame.switchControllers();
                }

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        writeButtonPressed(position, v);
                        break;
                    case MotionEvent.ACTION_UP:
                        writeButtonReleased(position, v);
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        writeButtonReleased(position, v);
                        break;
                    default:
                        break;
                }
                return true;
            }

        };

    }

    private void writeButtonPressed (int position, View v) {
        if (myButtonIDMap.containsKey(position)) {
            int code = myButtonIDMap.get((Integer) position);
            int action = AndroidButtonEvent.BUTTON_PRESSED;
            AndroidButton curButton = myButtonImageMap.get((Integer) position);
            curButton.setPressed(true);
            AndroidButtonEvent b = new AndroidButtonEvent(code, action);
            myMessenger.write(b);
            myVibrator.vibrate(PRESS_VIBRATE_TIME);
            ((ImageView) v).setImageResource(curButton.getDrawState());
            v.refreshDrawableState();
        }
    }

    private void writeButtonReleased (int position, View v) {
        if (myButtonIDMap.containsKey(position)) {
            int code = myButtonIDMap.get((Integer) position);
            int action = AndroidButtonEvent.BUTTON_RELEASED;
            AndroidButton curButton = myButtonImageMap.get((Integer) position);
            curButton.setPressed(false);
            AndroidButtonEvent b = new AndroidButtonEvent(code, action);
            myMessenger.write(b);
            myVibrator.vibrate(RELEASE_VIBRATE_TIME);
            ((ImageView) v).setImageResource(curButton.getDrawState());
            v.refreshDrawableState();
        }
    }

}